#include "trm/segment.h"
#include "xml/stream.h"
#include "imglib/hexcode.h"
#include "typelib/xml.h"
#include "read_enum.h"

static const char * refine_information_source_str[] = 
	{"reference", "target", "both", 0};
DEFINE_INLINE_ENUM_IO_OPERATORS(refine::information_source, refine_information_source_str);

static const char * mincut_information_source_str[] = 
	{"target", "both", 0};
DEFINE_INLINE_ENUM_IO_OPERATORS(trm::mincut::information_source, mincut_information_source_str);

static const char * preference_str[] = 
	{"none", "masked", "unmasked", 0};
DEFINE_INLINE_ENUM_IO_OPERATORS(refine::preference, preference_str);

static const char * smooth_mask_method_str[] = 
	{"0", /*"1", "2",*/ "4", /*"5", "E", "EA",*/ "equal_spheres", "equal_ellipses", /*"different_ellipses",*/ 0};
DEFINE_INLINE_ENUM_IO_OPERATORS(trm::smooth_mask_method, smooth_mask_method_str);

namespace trm {

#define Attr(x) s || xml::def_in_attr(#x, x, default_param.x);

xml::stream & param::serialize(xml::stream & s)
{
	Attr(reference_frame_pitch)
	Attr(downsample)

	Attr(optic_flow)
	Attr(max_motion)
	Attr(tracker_size)

	Attr(mincut)
	Attr(mincut_pyramid_levels)
	Attr(mincut_information_source)
	Attr(mincut_max_motion)
	Attr(mincut_max_link_distance)
	Attr(mincut_link_count)
	Attr(mincut_aspect)
	Attr(mincut_interframe_max_link_distance)
	Attr(mincut_interframe_link_count)
	Attr(mincut_antialiasing)
	Attr(mincut_antialiasing_levels_exp)

/*	Attr(entropic_tracker)
	Attr(entropic_best_move_iter_num)
	Attr(entropic_move_radius)
	Attr(entropic_band_radius)
	Attr(entropic_unambig_thr)
	Attr(entropic_alpha)
	Attr(entropic_sqrt_control)
	Attr(entropic_safe_time_step)*/

	Attr(refine_mask)
	Attr(refine_information_source)
	Attr(refine_window_half_size)
	Attr(refine_auto)
	Attr(refine_enough_statistics)
	Attr(refine_preference)

	Attr(refine2_mask)
	Attr(refine2_max_motion)
	Attr(refine2_max_level)

	/*Attr(refine3_mask)
	Attr(refine3_information_source)
	Attr(refine3_enough_statistics)
	Attr(refine3_preference)*/

	Attr(dilation_erosion)
	Attr(wool_removal)

	Attr(decrease_mask_freedom)
	Attr(decrease_freedom_degrees)
	Attr(decrease_smooth_contour)
	Attr(decrease_iterations)
	Attr(decrease_nodes_traction)
	Attr(decrease_tangents_traction)

	Attr(smooth_mask)
	Attr(smooth_window_half_size)
	Attr(smooth_passes_num)
	Attr(smooth_max_condition_number)
	//Attr(smooth_fore_depth)
	//Attr(smooth_back_depth)
	//Attr(smooth_sharpness)
	//Attr(smooth_noisiness)
	Attr(smooth_decorative)

	if (s.in()) {
		if (refine_enough_statistics < 1) {
			//the parameter was saved arguably in old version of Claxa, 
			//there it was relative to window size
			if (refine_window_half_size > 0) {
				float x;
				s || xml::attr("refine_enough_statistics", x);
				refine_enough_statistics = x * refine_total_window_pixels();
			}
		}
		put_within_the_limits();
	}

	return s;
}

xml::stream & twomasks::serialize(xml::stream & s)
{
	using namespace xml;
	s.child("bit_mask") || b;
	s.child("grey_mask") || g;
	s.child("contour") || children("control", contour);
	s || def_attr("ref_frame", ref_frame, -1);
	if (ref_frame != -1)
		s.child("motion") || motion;
	return s;
}

xml::stream & segment::serialize(xml::stream & s)
{
	using namespace xml;

	if (!_timing.in_use())
		s.child("timing") || _timing;

	s || attr("origin", _origin);
	//s || def_attr("key_mask_refined", _key_mask_refined, false); //move in CXSegment
	s.child("keymask") || _key_mask;
	s.child("param") || _param;

	node n = s.root();
	if (s.out()) {
		span sp = bit_masks_span().uniting(grey_masks_span());
		if (sp.size() > 0) {
			n.attr("first_data", sp.first);
			for (int i = sp.first; i != sp.last; ++i)
				s.child("twomasks") || *_masks[i - _accessible_span.first]; //*frame_masks(i);
		}
	}
	else {
		//in
		int first = n.attr("first_data", def(-1));
		if (first == -1) {
			_masks.clear();
			_accessible_span = span(_origin, _origin);
		}
		else {
			const_node_list list;
			n.children(list, "twomasks");
			_masks.resize(list.size());
			const_node_list::const_iterator l;
			int i;
			for (l = list.begin(), i = 0; l != list.end(); ++l, ++i) {
				_masks[i].reset(new twomasks);
				stream(*l) || *_masks[i];
			}
			_accessible_span = span(first, first + i);
		}
		find_bit_masks_span();
		find_grey_masks_span();
	}

	return s;
}

} //namespace trm
